const { Clutter, Gio, GObject, Meta, Shell, St } = imports.gi;
+const AppDisplay = imports.ui.appDisplay;
const Dash = imports.ui.dash;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
+const Util = imports.misc.util;
const ViewSelector = imports.ui.viewSelector;
const WindowManager = imports.ui.windowManager;
+const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
+const WorkspacesView = imports.ui.workspacesView;
+
+const SMALL_WORKSPACE_RATIO = 0.15;
var SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME;
var ControlsManagerLayout = GObject.registerClass(
class ControlsManagerLayout extends Clutter.BoxLayout {
- _init(searchEntry, viewSelector, dash, stateAdjustment) {
+ _init(searchEntry, appDisplay, workspacesDisplay, workspacesThumbnails,
+ viewSelector, dash, stateAdjustment) {
super._init({ orientation: Clutter.Orientation.VERTICAL });
+ this._appDisplay = appDisplay;
+ this._workspacesDisplay = workspacesDisplay;
+ this._workspacesThumbnails = workspacesThumbnails;
this._stateAdjustment = stateAdjustment;
this._searchEntry = searchEntry;
this._viewSelector = viewSelector;
stateAdjustment.connect('notify::value', () => this.layout_changed());
}
+ _getWorkspacesBoxForState(state, box, searchHeight, dashHeight, thumbnailsHeight) {
+ const workspaceBox = box.copy();
+ const [width, height] = workspaceBox.get_size();
+ const { spacing } = this;
+
+ switch (state) {
+ case ControlsState.HIDDEN:
+ break;
+ case ControlsState.WINDOW_PICKER:
+ workspaceBox.set_origin(0,
+ searchHeight + spacing +
+ (thumbnailsHeight > 0 ? thumbnailsHeight + spacing : 0));
+ workspaceBox.set_size(width,
+ height -
+ dashHeight - spacing -
+ searchHeight - spacing -
+ (thumbnailsHeight > 0 ? thumbnailsHeight + spacing : 0));
+ break;
+ case ControlsState.APP_GRID:
+ workspaceBox.set_origin(0, searchHeight + spacing);
+ workspaceBox.set_size(
+ width,
+ Math.round(Math.max(height * SMALL_WORKSPACE_RATIO)));
+ break;
+ }
+
+ return workspaceBox;
+ }
+
vfunc_set_container(container) {
this._container = container;
this.hookup_style(container);
availableHeight -= dashHeight + spacing;
- // ViewSelector
- const initialBox = new Clutter.ActorBox();
- initialBox.set_origin(0, 0);
- initialBox.set_size(width, height);
+ // Workspace Thumbnails
+ let thumbnailsHeight = 0;
+ if (this._workspacesThumbnails.visible) {
+ [thumbnailsHeight] =
+ this._workspacesThumbnails.get_preferred_height(width);
+ thumbnailsHeight = Math.min(
+ thumbnailsHeight,
+ height * WorkspaceThumbnail.MAX_THUMBNAIL_SCALE);
+ childBox.set_origin(0, searchHeight + spacing);
+ childBox.set_size(width, thumbnailsHeight);
+ this._workspacesThumbnails.allocate(childBox);
+ }
+
+ // Workspaces
+ const params = [box, searchHeight, dashHeight, thumbnailsHeight];
+ const transitionParams = this._stateAdjustment.getStateTransitionParams();
+
+ let workspacesBox;
+ if (!transitionParams.transitioning) {
+ workspacesBox =
+ this._getWorkspacesBoxForState(transitionParams.currentState, ...params);
+ } else {
+ const initialBox =
+ this._getWorkspacesBoxForState(transitionParams.initialState, ...params);
+ const finalBox =
+ this._getWorkspacesBoxForState(transitionParams.finalState, ...params);
+ workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress);
+ }
+
+ this._workspacesDisplay.allocate(workspacesBox);
+
+ // AppDisplay
+ const workspaceAppGridBox =
+ this._getWorkspacesBoxForState(ControlsState.APP_GRID, ...params);
+
+ childBox.set_origin(0, searchHeight + spacing + workspaceAppGridBox.get_height());
+ childBox.set_size(width,
+ height -
+ searchHeight - spacing -
+ workspaceAppGridBox.get_height() - spacing -
+ dashHeight);
+
+ this._appDisplay.allocate(childBox);
+ // ViewSelector
childBox.set_origin(0, searchHeight + spacing);
childBox.set_size(width, availableHeight);
- const page = this._viewSelector.getActivePage();
- const progress = page === ViewSelector.ViewPage.SEARCH
- ? 1 : Math.min(this._stateAdjustment.value, 1);
- const viewSelectorBox = initialBox.interpolate(childBox, progress);
- this._viewSelector.allocate(viewSelectorBox);
+ this._viewSelector.allocate(childBox);
}
});
});
this._stateAdjustment = new OverviewAdjustment(this);
+ this._stateAdjustment.connect('notify::value', this._update.bind(this));
this._nWorkspacesNotifyId =
workspaceManager.connect('notify::n-workspaces',
this._updateAdjustment.bind(this));
this.viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
+ this.dash.showAppsButton);
+ this.viewSelector.connect('page-empty', this._onPageEmpty.bind(this));
+
+ this._thumbnailsBox =
+ new WorkspaceThumbnail.ThumbnailsBox(this._workspaceAdjustment);
+ this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay(
this._workspaceAdjustment,
- this.dash.showAppsButton,
this._stateAdjustment);
+ this._appDisplay = new AppDisplay.AppDisplay();
this.add_child(searchEntryBin);
+ this.add_child(this._appDisplay);
this.add_child(this.dash);
this.add_child(this.viewSelector);
+ this.add_child(this._thumbnailsBox);
+ this.add_child(this._workspacesDisplay);
this.layout_manager = new ControlsManagerLayout(searchEntryBin,
- this.viewSelector, this.dash, this._stateAdjustment);
+ this._appDisplay,
+ this._workspacesDisplay,
+ this._thumbnailsBox,
+ this.viewSelector,
+ this.dash,
+ this._stateAdjustment);
this.dash.showAppsButton.connect('notify::checked',
this._onShowAppsButtonToggled.bind(this));
+ Main.ctrlAltTabManager.addGroup(
+ this.appDisplay,
+ _('Applications'),
+ 'view-app-grid-symbolic', {
+ proxy: this,
+ focusCallback: () => {
+ this.dash.showAppsButton.checked = true;
+ this.appDisplay.navigate_focus(
+ null, St.DirectionType.TAB_FORWARD, false);
+ },
+ });
+
+ Main.ctrlAltTabManager.addGroup(
+ this._workspacesDisplay,
+ _('Windows'),
+ 'focus-windows-symbolic', {
+ proxy: this,
+ focusCallback: () => {
+ this.dash.showAppsButton.checked = false;
+ this._workspacesDisplay.navigate_focus(
+ null, St.DirectionType.TAB_FORWARD, false);
+ },
+ });
+
Main.wm.addKeybinding(
'toggle-application-view',
new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }),
this._toggleAppsPage.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
+
+ this._update();
+ }
+
+ _getFitModeForState(state) {
+ switch (state) {
+ case ControlsState.HIDDEN:
+ case ControlsState.WINDOW_PICKER:
+ return WorkspacesView.FitMode.SINGLE;
+ case ControlsState.APP_GRID:
+ return WorkspacesView.FitMode.ALL;
+ default:
+ return WorkspacesView.FitMode.SINGLE;
+ }
+ }
+
+ _getThumbnailsBoxParams() {
+ const { initialState, finalState, progress } =
+ this._stateAdjustment.getStateTransitionParams();
+
+ const paramsForState = s => {
+ let opacity, scale, translationY;
+ switch (s) {
+ case ControlsState.HIDDEN:
+ case ControlsState.WINDOW_PICKER:
+ opacity = 255;
+ scale = 1;
+ translationY = 0;
+ break;
+ case ControlsState.APP_GRID:
+ opacity = 0;
+ scale = 0.5;
+ translationY = this._thumbnailsBox.height / 2;
+ break;
+ default:
+ opacity = 255;
+ scale = 1;
+ translationY = 0;
+ break;
+ }
+
+ return { opacity, scale, translationY };
+ };
+
+ const initialParams = paramsForState(initialState);
+ const finalParams = paramsForState(finalState);
+
+ return [
+ Util.lerp(initialParams.opacity, finalParams.opacity, progress),
+ Util.lerp(initialParams.scale, finalParams.scale, progress),
+ Util.lerp(initialParams.translationY, finalParams.translationY, progress),
+ ];
+ }
+
+ _updateThumbnailsBox(animate = false) {
+ const page = this.viewSelector.getActivePage();
+ const searching = page === ViewSelector.ViewPage.SEARCH;
+ const [opacity, scale, translationY] = this._getThumbnailsBoxParams();
+
+ const thumbnailsBoxVisible = !searching && opacity !== 0;
+ if (thumbnailsBoxVisible) {
+ this._thumbnailsBox.opacity = 0;
+ this._thumbnailsBox.visible = thumbnailsBoxVisible;
+ }
+
+ const params = {
+ opacity: searching ? 0 : opacity,
+ duration: animate ? SIDE_CONTROLS_ANIMATION_TIME : 0,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => (this._thumbnailsBox.visible = thumbnailsBoxVisible),
+ };
+
+ if (!searching) {
+ params.scale_x = scale;
+ params.scale_y = scale;
+ params.translation_y = translationY;
+ }
+
+ this._thumbnailsBox.ease(params);
+ }
+
+ _update() {
+ const params = this._stateAdjustment.getStateTransitionParams();
+
+ const fitMode = Util.lerp(
+ this._getFitModeForState(params.initialState),
+ this._getFitModeForState(params.finalState),
+ params.progress);
+
+ const { fitModeAdjustment } = this._workspacesDisplay;
+ fitModeAdjustment.value = fitMode;
+
+ this._updateThumbnailsBox();
+ }
+
+ _onPageEmpty() {
+ const page = this.viewSelector.getActivePage();
+ const isActivities = page === ViewSelector.ViewPage.ACTIVITIES;
+
+ if (isActivities) {
+ this._appDisplay.show();
+ this._workspacesDisplay.reactive = true;
+ this._workspacesDisplay.setPrimaryWorkspaceVisible(true);
+ } else {
+ this.viewSelector.show();
+ }
+
+ this._updateThumbnailsBox(true);
+
+ this._appDisplay.ease({
+ opacity: isActivities ? 255 : 0,
+ duration: SIDE_CONTROLS_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => (this._appDisplay.visible = isActivities),
+ });
+ this._workspacesDisplay.ease({
+ opacity: isActivities ? 255 : 0,
+ duration: SIDE_CONTROLS_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => {
+ this._workspacesDisplay.reactive = isActivities;
+ this._workspacesDisplay.setPrimaryWorkspaceVisible(isActivities);
+ },
+ });
+ this.viewSelector.ease({
+ opacity: isActivities ? 0 : 255,
+ duration: SIDE_CONTROLS_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => (this.viewSelector.visible = !isActivities),
+ });
}
_onShowAppsButtonToggled() {
this._workspaceAdjustment.value = activeIndex;
}
+ vfunc_unmap() {
+ this._workspacesDisplay.hide();
+ super.vfunc_unmap();
+ }
+
animateToOverview(state, callback) {
this._ignoreShowAppsButtonToggle = true;
this.viewSelector.prepareToEnterOverview();
+ this._workspacesDisplay.prepareToEnterOverview();
+ if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
+ Main.overview.fadeOutDesktop();
this._stateAdjustment.value = ControlsState.HIDDEN;
this._stateAdjustment.ease(state, {
animateFromOverview(callback) {
this._ignoreShowAppsButtonToggle = true;
- this.viewSelector.prepareToLeaveOverview();
+ this._workspacesDisplay.prepareToLeaveOverview();
+ if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
+ Main.overview.fadeInDesktop();
this._stateAdjustment.ease(ControlsState.HIDDEN, {
duration: Overview.ANIMATION_TIME,
get searchEntry() {
return this._searchEntry;
}
+
+ get appDisplay() {
+ return this._appDisplay;
+ }
});
const { Clutter, GObject, Shell, St } = imports.gi;
-const AppDisplay = imports.ui.appDisplay;
const Main = imports.ui.main;
const OverviewControls = imports.ui.overviewControls;
const Search = imports.ui.search;
const ShellEntry = imports.ui.shellEntry;
-const Util = imports.misc.util;
-const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
-const WorkspacesView = imports.ui.workspacesView;
var ViewPage = {
ACTIVITIES: 1,
return terms;
}
-
-var ActivitiesContainer = GObject.registerClass(
-class ActivitiesContainer extends St.Widget {
- _init(thumbnailsBox, workspacesDisplay, appDisplay, overviewAdjustment) {
- super._init();
-
- // 0 for window picker, 1 for app grid
- this._adjustment = new St.Adjustment({
- actor: this,
- value: 0,
- lower: 0,
- upper: 1,
- });
- this._adjustment.connect('notify::value', () => {
- this._update();
- this.queue_relayout();
- });
-
- overviewAdjustment.connect('notify::value', () => {
- const { ControlsState } = OverviewControls;
-
- const overviewState = overviewAdjustment.value;
-
- this._appDisplay.visible =
- overviewState >= ControlsState.WINDOW_PICKER;
- this._adjustment.value = Math.max(0,
- overviewAdjustment.value - ControlsState.WINDOW_PICKER);
- });
-
- this._thumbnailsBox = thumbnailsBox;
- this.add_child(thumbnailsBox);
-
- this._appDisplay = appDisplay;
- this.add_child(appDisplay);
-
- this._workspacesDisplay = workspacesDisplay;
- this.add_child(workspacesDisplay);
-
- this.connect('notify::mapped', () => {
- workspacesDisplay.setPrimaryWorkspaceVisible(this.mapped);
- });
-
- this._update();
- }
-
- _update() {
- const progress = this._adjustment.value;
-
- this._appDisplay.opacity = progress * 255;
-
- this._thumbnailsBox.set({
- scale_x: Util.lerp(1, 0.5, progress),
- scale_y: Util.lerp(1, 0.5, progress),
- translation_y: Util.lerp(0, this._thumbnailsBox.height, progress),
- opacity: Util.lerp(0, 255, 1 - progress),
- visible: (1 - progress) !== 0,
- });
-
- const { fitModeAdjustment } = this._workspacesDisplay;
- fitModeAdjustment.value = Util.lerp(
- WorkspacesView.FitMode.SINGLE,
- WorkspacesView.FitMode.ALL,
- progress);
- }
-
- _getWorkspacesBoxes(box, thumbnailsHeight) {
- const initialBox = box.copy();
- initialBox.y1 += thumbnailsHeight;
-
- const finalBox = box.copy();
- finalBox.set_size(
- box.get_width(),
- Math.round(box.get_height() * 0.15));
-
- return [initialBox, finalBox];
- }
-
- vfunc_allocate(box) {
- this.set_allocation(box);
-
- // Workspace Thumbnails
- let thumbnailsHeight = 0;
- if (this._thumbnailsBox.visible) {
- const maxThumbnailScale = WorkspaceThumbnail.MAX_THUMBNAIL_SCALE;
- const primaryMonitor = Main.layoutManager.primaryMonitor;
- const [width, height] = box.get_size();
-
- [, thumbnailsHeight] =
- this._thumbnailsBox.get_preferred_height(width);
- thumbnailsHeight = Math.min(
- thumbnailsHeight,
- (primaryMonitor ? primaryMonitor.height : height) * maxThumbnailScale);
-
- const thumbnailsBox = new Clutter.ActorBox();
- thumbnailsBox.set_origin(0, 0);
- thumbnailsBox.set_size(width, thumbnailsHeight);
- this._thumbnailsBox.allocate(thumbnailsBox);
- }
-
- const progress = this._adjustment.value;
- const [initialBox, finalBox] =
- this._getWorkspacesBoxes(box, thumbnailsHeight);
- const workspacesBox = initialBox.interpolate(finalBox, progress);
- this._workspacesDisplay.allocate(workspacesBox);
-
- if (this._appDisplay.visible) {
- const appDisplayBox = box.copy();
- appDisplayBox.y1 += Math.ceil(finalBox.get_height());
- this._appDisplay.allocate(appDisplayBox);
- }
- }
-});
-
var ViewSelector = GObject.registerClass({
Signals: {
'page-changed': {},
'page-empty': {},
},
}, class ViewSelector extends Shell.Stack {
- _init(searchEntry, workspaceAdjustment, showAppsButton, overviewAdjustment) {
+ _init(searchEntry, showAppsButton) {
super._init({
name: 'viewSelector',
x_expand: true,
this._iconClickedId = 0;
this._capturedEventId = 0;
- this._thumbnailsBox =
- new WorkspaceThumbnail.ThumbnailsBox(workspaceAdjustment);
- this._workspacesDisplay =
- new WorkspacesView.WorkspacesDisplay(workspaceAdjustment, overviewAdjustment);
- this.appDisplay = new AppDisplay.AppDisplay();
-
- const activitiesContainer = new ActivitiesContainer(
- this._thumbnailsBox,
- this._workspacesDisplay,
- this.appDisplay,
- overviewAdjustment);
+ const dummy = new St.Widget();
this._activitiesPage =
- this._addPage(activitiesContainer, _('Activities'), 'view-app-grid-symbolic');
-
- Main.ctrlAltTabManager.addGroup(
- this.appDisplay,
- _('Applications'),
- 'edit-find-symbolic', {
- proxy: this,
- focusCallback: () => {
- this._showPage(this._activitiesPage);
- this._showAppsButton.checked = true;
- this.appDisplay.navigate_focus(
- null, St.DirectionType.TAB_FORWARD, false);
- },
- });
-
- Main.ctrlAltTabManager.addGroup(
- this._workspacesDisplay,
- _('Windows'),
- 'focus-windows-symbolic', {
- proxy: this,
- focusCallback: () => {
- this._showPage(this._activitiesPage);
- this._showAppsButton.checked = false;
- this._workspacesDisplay.navigate_focus(
- null, St.DirectionType.TAB_FORWARD, false);
- },
- });
+ this._addPage(dummy, _('Activities'), 'view-app-grid-symbolic');
this._searchResults = new Search.SearchResultsView();
this._searchPage = this._addPage(this._searchResults);
}
prepareToEnterOverview() {
- this.show();
this.reset();
- this._workspacesDisplay.prepareToEnterOverview();
this._activePage = null;
this._showPage(this._activitiesPage);
-
- if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
- Main.overview.fadeOutDesktop();
- }
-
- prepareToLeaveOverview() {
- this._workspacesDisplay.prepareToLeaveOverview();
-
- if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
- Main.overview.fadeInDesktop();
}
- vfunc_hide() {
+ vfunc_unmap() {
this.reset();
- this._workspacesDisplay.hide();
- super.vfunc_hide();
+ super.vfunc_unmap();
}
_addPage(actor) {